package com.byox.drawviewproject.slice;

import com.byox.drawview.enums.DrawingCapture;
import com.byox.drawview.enums.DrawingMode;
import com.byox.drawview.enums.DrawingTool;
import com.byox.drawview.views.DrawView;
import com.byox.drawviewproject.MainAbility;
import com.byox.drawviewproject.ResourceTable;
import com.byox.drawviewproject.component.HmPopuWindow;
import com.byox.drawviewproject.dialogs.DrawAttribsDialog;
import com.byox.drawviewproject.dialogs.RequestTextDialog;
import com.byox.drawviewproject.dialogs.SaveBitmapDialog;
import com.byox.drawviewproject.moudle.PopuContentInfo;
import com.byox.drawviewproject.util.CreatPopuData;
import com.byox.drawviewproject.util.PopuValue;
import com.github.clans.fab.FloatingActionButton;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.*;
import ohos.media.image.ImageReceiver;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.ImageFormat;
import ohos.media.image.common.Size;

import java.nio.ByteBuffer;
import java.util.List;

import static ohos.media.camera.device.Camera.FrameConfigType.FRAME_CONFIG_PREVIEW;

public class CameraAbilitySlice extends AbilitySlice implements Component.ClickedListener, ImageReceiver.IImageArrivalListener {
    private static final int IMAGE_RCV_CAPACITY = 9;
    private Context mContex;
    private CameraKit cameraKit;
    private SurfaceProvider surfaceProvider;
    private Camera cameraDevice;
    private Surface previewSurface;
    private FrameConfig.Builder framePreviewConfigBuilder;
    private ImageReceiver imageReceiver;
    private PixelMap cameraPixelMap;
    // CONSTANTS
    private final int STORAGE_PERMISSIONS = 1000;
    private final int CAMERA_PERMISSIONS = 3000;
    private Image muneOne;
    private Image muneTwo;
    private Image muneThree;
    private DrawView mDrawView;
    private FloatingActionButton mFabClearDraw;
    private Text toastText;
    private int cbInitTopMargin;
    private boolean flag = false;
    private AnimatorValue animatorValue;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_camera);
        initView();
    }

    private void initView() {
        mContex = this;
        muneOne = (Image) findComponentById(ResourceTable.Id_mune_one);
        muneOne.setClickedListener(this);
        muneTwo = (Image) findComponentById(ResourceTable.Id_mune_two);
        muneTwo.setClickedListener(this);
        muneThree = (Image) findComponentById(ResourceTable.Id_mune_three);
        muneThree.setClickedListener(this);
        mDrawView = (DrawView) findComponentById(ResourceTable.Id_draw_view);
        mFabClearDraw = (FloatingActionButton) findComponentById(ResourceTable.Id_fab_clear);
        cbInitTopMargin = mFabClearDraw.getMarginBottom();
        toastText = (Text) findComponentById(ResourceTable.Id_toastText);
        initSurface();
        setListeners();
        animatorValue = new AnimatorValue();
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    private void openCamera() {
        // 获取CameraKit对象
        cameraKit = CameraKit.getInstance(mContex);
        if (cameraKit == null) {
            // 处理cameraKit获取失败的情况
        } else {
            EventHandler eventHandler = new EventHandler(EventRunner.create("CameraCb"));
            String[] cameraList = cameraKit.getCameraIds();
            String cameraId = null;
            for (
                    String id : cameraList) {
                //获取后置摄像头
                if (cameraKit.getCameraInfo(id).getFacingType() == CameraInfo.FacingType.CAMERA_FACING_BACK) {
                    cameraId = id;
                }
            }
            if (cameraId == null) {
                return;
            }
            //创建图像接收器
            //获取支持分辨率
            CameraAbility cameraAbility = cameraKit.getCameraAbility(cameraId);
            List<Size> supportedSizes = cameraAbility.getSupportedSizes(SurfaceOps.class);
            Size size = supportedSizes.get(0);
            //创建图像接收器
            imageReceiver = ImageReceiver.create(Math.max(size.width, size.height), Math.min(size.width, size.height), ImageFormat.JPEG, 5);
            imageReceiver.setImageArrivalListener(this);
            cameraKit.createCamera(cameraId, new CameraStateCallbackImpl(), eventHandler);
        }
    }

    private void initSurface() {
        getWindow().setTransparent(true);
        surfaceProvider = new SurfaceProvider(this);
        DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(
            ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        surfaceProvider.setLayoutConfig(params);
        surfaceProvider.pinToZTop(false);
        surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack());
        ((DependentLayout)
            findComponentById(ResourceTable.Id_draw_cam_view)).addComponent(surfaceProvider);
    }

    @Override
    public void onImageArrival(ImageReceiver imageReceiver) {
        System.out.println("======onImageArrival======");
        try {
            ohos.media.image.Image image = imageReceiver.readLatestImage();
            if (image == null) {
                return;
            }
            ohos.media.image.Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG);
            byte[] bytes = new byte[component.remaining()];
            ByteBuffer buffer = component.getBuffer();
            buffer.get(bytes);
            ImageSource imageSource = ImageSource.create(bytes, new ImageSource.SourceOptions());
            ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
            PixelMap pixelMap = imageSource.createPixelmap(options);
            PixelMap.InitializationOptions initOptions = new PixelMap.InitializationOptions();
            int width = pixelMap.getImageInfo().size.width;
            int height = pixelMap.getImageInfo().size.height;
            initOptions.size = new Size(width, height);
            cameraPixelMap = PixelMap.create(initOptions);
            initOptions.editable = true;
            Texture texture = new Texture(cameraPixelMap);
            Canvas canvas = new Canvas(texture);
            canvas.rotate(90, width/2f, height/2f);
            canvas.drawPixelMapHolder(new PixelMapHolder(pixelMap), 0, 0, new Paint());
            image.release();
        } catch (Exception e) {
            System.out.println("====Exception=" + e.getMessage());
        }
    }

    private final class CameraStateCallbackImpl extends CameraStateCallback {
        @Override
        public void onCreated(Camera camera) {
            System.out.println("======onCreated======");
            // 创建相机设备
            if (surfaceProvider == null) {
                return;
            }
            previewSurface = surfaceProvider.getSurfaceOps().get().getSurface();
            if (previewSurface == null) {
                return;
            }
            // 获取相机配置模板
            CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder();
            // 配置预览的Surface
            cameraConfigBuilder.addSurface(previewSurface);
            // 配置图像接收
            cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            camera.configure(cameraConfigBuilder.build());
            cameraDevice = camera;
        }

        @Override
        public void onConfigured(Camera camera) {
            System.out.println("======onConfigured======");
            // 获取预览配置模板
            framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW);
            // 配置预览Surface
            framePreviewConfigBuilder.addSurface(previewSurface);
            // 配置图像接收
            framePreviewConfigBuilder.addSurface(imageReceiver.getRecevingSurface());
            // 启动循环帧捕获
            camera.triggerLoopingCapture(framePreviewConfigBuilder.build());
        }

    }

    class SurfaceCallBack implements SurfaceOps.Callback {
        @Override
        public void surfaceCreated(SurfaceOps callbackSurfaceOps) {
            int width = DisplayManager.getInstance().getDefaultDisplay(CameraAbilitySlice.this).get().getRealAttributes().width;
            int height = DisplayManager.getInstance().getDefaultDisplay(CameraAbilitySlice.this).get().getRealAttributes().height;
            callbackSurfaceOps.setFixedSize(Math.max(width, height), Math.min(width, height));//设置分辨率 防止拉伸
            getUITaskDispatcher().asyncDispatch(() -> {
                openCamera();
            });

        }

        @Override
        public void surfaceChanged(SurfaceOps callbackSurfaceOps, int format, int width, int height) {
        }

        @Override
        public void surfaceDestroyed(SurfaceOps callbackSurfaceOps) {

        }
    }
    @Override
    public void onClick(Component component) {
       switch (component.getId()) {
           case ResourceTable.Id_mune_one:
               System.out.println("mDrawView============" + mDrawView.canUndo());
               if (mDrawView.canUndo()) {
                   mDrawView.undo();
                   canUndoRedo();
               }
               break;
           case ResourceTable.Id_mune_two:
               if (mDrawView.canRedo()) {
                   mDrawView.redo();
                   canUndoRedo();
               }
               break;
           case ResourceTable.Id_mune_three:
               Component componentTwo = LayoutScatter.getInstance(this).parse(ResourceTable.Layout_popu_list,
                   null, false);
               String[] popuTwoTexts = getStringArray(ResourceTable.Strarray_popu_camra_texts);
               int[] images = new int[]{ResourceTable.Media_ic_action_palette, ResourceTable.Media_ic_action_brush
                   , ResourceTable.Media_ic_action_edit, ResourceTable.Media_ic_action_save
                   , ResourceTable.Media_ic_action_format_paint};
               List<PopuContentInfo> popuTwoContentInfos = CreatPopuData.initPopuData(images, popuTwoTexts, null);
               HmPopuWindow hmPopuWindowTwo = new HmPopuWindow(this, componentTwo, 550
                   , 1000, popuTwoContentInfos);
               popuItemClick(hmPopuWindowTwo);
               hmPopuWindowTwo.customShow(0);
               break;
       }
    }

    private void popuItemClick(HmPopuWindow hmPopuWindow) {
        hmPopuWindow.getListContainer().setItemClickedListener(new ListContainer.ItemClickedListener() {
            @Override
            public void onItemClicked(ListContainer listContainer, Component component, int index, long l) {
                switch (index) {
                    case PopuValue.DRAWATTRIBUTES:
                        DrawAttribsDialog drawAttribsDialog = new DrawAttribsDialog(CameraAbilitySlice.this
                            , null);
                        drawAttribsDialog.setPaint(mDrawView.getCurrentPaintParams());
                        drawAttribsDialog.setOnCustomViewDialogListener(new DrawAttribsDialog.OnCustomViewDialogListener() {
                            @Override
                            public void onRefreshPaint(Paint newPaint) {
                                mDrawView.setDrawColor(newPaint.getColor().getValue())
                                    .setPaintStyle(newPaint.getStyle())
                                    .setDither(newPaint.getDither())
                                    .setDrawWidth((int) newPaint.getStrokeWidth())
                                    .setDrawAlpha(newPaint.getAlpha())
                                    .setAntiAlias(newPaint.isAntiAlias())
                                    .setLineCap(newPaint.getStrokeCap())
                                    .setFontFamily(newPaint.getFont())
                                    .setFontSize(newPaint.getTextSize());
                            }
                        });
                        drawAttribsDialog.show();
                        break;
                    case PopuValue.BACKGROUNDIMAGE:
                        showDrawTollPopu();
                        break;
                    case PopuValue.DRAWTOOL:
                        showDrawModePopu();
                        break;
                    case PopuValue.DRAWMODE:
                        Component saveBitmap = LayoutScatter.getInstance(mContex).parse(ResourceTable.Layout_save_bitmap,
                            null, false);
                        SaveBitmapDialog dialog = SaveBitmapDialog.newInstance(mContex, saveBitmap, 900
                            , ComponentContainer.LayoutConfig.MATCH_CONTENT);
                        Object[] createCaptureResponse = mDrawView.createCapture(DrawingCapture.BITMAP);
                        dialog.setCameraPixMap(cameraPixelMap);
                        dialog.setPreviewBitmap((PixelMap) createCaptureResponse[0]);
                        dialog.setPreviewFormat(String.valueOf(createCaptureResponse[1]));
                        dialog.setOnSaveBitmapListener(new SaveBitmapDialog.OnSaveBitmapListener() {
                            @Override
                            public void onSaveBitmapCompleted() {
                                toastText.setText("Capture saved succesfully!");
                                showToastView();
                            }

                            @Override
                            public void onSaveBitmapCanceled() {
                                toastText.setText("Capture saved canceled.");
                                showToastView();
                            }
                        });
                        dialog.show();
                        break;
                    case PopuValue.SAVEDRAW:
                        Intent intent = new Intent();
                        Operation operation = new Intent.OperationBuilder()
                            .withDeviceId("")
                            .withBundleName(getAbilityPackageContext().getBundleName())
                            .withAbilityName(MainAbility.class.getName())
                            .build();
                        intent.setOperation(operation);
                        startAbility(intent);
                        CameraAbilitySlice.this.terminateAbility();
                        break;
                }
                hmPopuWindow.destroy();
            }
        });
    }

    private void showDrawTollPopu() {
        Component drawtoolComponent = LayoutScatter.getInstance(CameraAbilitySlice.this).parse(ResourceTable.Layout_popu_draw_list,
            null, false);
        String[] popuDrawtoolTexts = getStringArray(ResourceTable.Strarray_popu_drawtool_texts);
        List<PopuContentInfo> popuTwoContentInfos = CreatPopuData.initPopuData(null, popuDrawtoolTexts, null);
        HmPopuWindow hmPopuWindowDrawtool = new HmPopuWindow(CameraAbilitySlice.this, drawtoolComponent, 900
            , 1400, popuTwoContentInfos);
        hmPopuWindowDrawtool.setAlignment(LayoutAlignment.CENTER);
        hmPopuWindowDrawtool.customShow(2);
        popuDrawToolItemClick(hmPopuWindowDrawtool, popuDrawtoolTexts);
    }


    private void popuDrawToolItemClick(HmPopuWindow hmPopuWindow, String[] popuDrawtoolTexts) {
        hmPopuWindow.getListContainer().setItemClickedListener(new ListContainer.ItemClickedListener() {
            @Override
            public void onItemClicked(ListContainer listContainer, Component component, int position, long l) {
                mDrawView.setDrawingTool(DrawingTool.values()[position]);
                hmPopuWindow.destroy();
            }
        });
    }

    private void showDrawModePopu() {
        Component drawtoolComponent = LayoutScatter.getInstance(CameraAbilitySlice.this).parse(ResourceTable.Layout_popu_draw_list,
            null, false);
        Text text = (Text) drawtoolComponent.findComponentById(ResourceTable.Id_text);
        text.setText("Select a draw mode");
        String[] popuDrawtoolTexts = getStringArray(ResourceTable.Strarray_popu_drawmode_texts);
        List<PopuContentInfo> popuTwoContentInfos = CreatPopuData.initPopuData(null, popuDrawtoolTexts, null);
        HmPopuWindow hmPopuWindowDrawtool = new HmPopuWindow(CameraAbilitySlice.this, drawtoolComponent, 800
            , 800, popuTwoContentInfos);
        hmPopuWindowDrawtool.setAlignment(LayoutAlignment.CENTER);
        hmPopuWindowDrawtool.customShow(2);
        popuDrawModeItemClick(hmPopuWindowDrawtool, popuDrawtoolTexts);
    }

    private void popuDrawModeItemClick(HmPopuWindow hmPopuWindow, String[] popuDrawtoolTexts) {
        hmPopuWindow.getListContainer().setItemClickedListener(new ListContainer.ItemClickedListener() {
            @Override
            public void onItemClicked(ListContainer listContainer, Component component, int position, long l) {
                mDrawView.setDrawingMode(DrawingMode.values()[position]);
                hmPopuWindow.destroy();
            }
        });
    }

    private void setListeners() {
        mDrawView.setOnDrawViewListener(new DrawView.OnDrawViewListener() {
            @Override
            public void onStartDrawing() {
                canUndoRedo();
            }
            @Override
            public void onEndDrawing() {
                canUndoRedo();
                if (mFabClearDraw.getVisibility() == Component.INVISIBLE) {
                    mFabClearDraw.setVisibility(Component.VISIBLE);
                    handlerFabClearDraw(true, 0f, 0f, 1f, 1f);
                }
            }

            @Override
            public void onClearDrawing() {
                canUndoRedo();
                if (mFabClearDraw.getVisibility() == Component.VISIBLE) {
                    handlerFabClearDraw(false, 1f, 1f, 0f, 0f);
                }
            }

            @Override
            public void onRequestText() {
                Component component = LayoutScatter.getInstance(mContex).parse(ResourceTable.Layout_request_text,
                    null, false);
                RequestTextDialog requestTextDialog = new RequestTextDialog(mContex, component, 1000
                    , ComponentContainer.LayoutConfig.MATCH_CONTENT);
                requestTextDialog.show();
                requestTextDialog.setOnRequestTextListener(new RequestTextDialog.OnRequestTextListener() {
                    @Override
                    public void onRequestTextConfirmed(String requestedText) {
                        mDrawView.refreshLastText(requestedText);
                    }
                    @Override
                    public void onRequestTextCancelled() {
                        mDrawView.cancelTextRequest();
                    }
                });
            }

            @Override
            public void onAllMovesPainted() {

            }
        });

        mFabClearDraw.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                clearDraw();
            }
        });
    }

    private void clearDraw() {
        mDrawView.restartDrawing();
    }

    private void canUndoRedo() {
        if (!mDrawView.canUndo()) {
            muneOne.setClickable(false);
            muneOne.setPixelMap(ResourceTable.Media_ic_action_content_undo_disabled);
        } else {
            muneOne.setClickable(true);
            muneOne.setPixelMap(ResourceTable.Media_ic_action_content_undo);
        }
        if (!mDrawView.canRedo()) {
            muneTwo.setClickable(false);
            muneTwo.setPixelMap(ResourceTable.Media_ic_action_content_redo_disabled);
        } else {
            muneTwo.setClickable(true);
            muneTwo.setPixelMap(ResourceTable.Media_ic_action_content_redo);
        }
    }

    private void handlerFabClearDraw(boolean visiable, float fromScaleX, float fromScaleY, float toScaleX
        , float toScaleY) {
        mFabClearDraw.setPivot(mFabClearDraw.getWidth() / 2f, mFabClearDraw.getHeight() / 2f);
        AnimatorProperty ap = new AnimatorProperty();
        if (!visiable) {
            ap.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator animator) {

                }

                @Override
                public void onStop(Animator animator) {

                }

                @Override
                public void onCancel(Animator animator) {

                }

                @Override
                public void onEnd(Animator animator) {
                    mFabClearDraw.setVisibility(Component.INVISIBLE);
                }

                @Override
                public void onPause(Animator animator) {

                }

                @Override
                public void onResume(Animator animator) {

                }
            });
        }
        ap.setTarget(mFabClearDraw)
            .scaleXFrom(fromScaleX).scaleYFrom(fromScaleY)
            .scaleX(toScaleX).scaleY(toScaleY)
            .setDuration(300).start();
    }

    private void showToastView() {
        animatorValue.setDuration(200);
        if (flag) {
            animatorValue.setDelay(2500);
        }
        animatorValue.setStateChangedListener(new MyAnimationStateChange());
        animatorValue.setValueUpdateListener(new MyAnimationValueListener());
        animatorValue.start();
    }

    private class MyAnimationValueListener implements AnimatorValue.ValueUpdateListener {
        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {
            if(!flag){
                float topMargin = (v - 1) * toastText.getHeight();
                float cbtopMargin = v * toastText.getHeight();
                toastText.setMarginBottom((int)topMargin);
                mFabClearDraw.setMarginBottom((int)(cbInitTopMargin  + cbtopMargin));
            }else {
                float topMargin = -v * toastText.getHeight();
                toastText.setMarginBottom((int)topMargin);
                mFabClearDraw.setMarginBottom((int)(cbInitTopMargin  + topMargin));
            }
        }
    }

    private class MyAnimationStateChange implements Animator.StateChangedListener{

        @Override
        public void onStart(Animator animator) {

        }

        @Override
        public void onStop(Animator animator) {

        }

        @Override
        public void onCancel(Animator animator) {

        }

        @Override
        public void onEnd(Animator animator) {
            if (flag) {
                flag = false;
            }else {
                flag = true;
                showToastView();
            }
            animatorValue.setDelay(0);
            cbInitTopMargin = mFabClearDraw.getMarginBottom();
        }

        @Override
        public void onPause(Animator animator) {

        }

        @Override
        public void onResume(Animator animator) {

        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (cameraDevice != null) {
            framePreviewConfigBuilder = null;
            try {
                cameraDevice.release();
                cameraDevice = null;
                surfaceProvider.clearFocus();
                surfaceProvider.removeFromWindow();
                surfaceProvider = null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}
